df <- read_csv('../ocean-waves.csv')
dir.breaks <- seq(0, 360, length.out=9)
dir.labels <- c('N','NE','E','SE','S','SW','W','NW','')
Distribution of direction per location
p1 <- ggplot(df, aes(RottDirection, fill=after_stat(count))) +
geom_histogram(binwidth=5) +
coord_polar() +
scale_fill_viridis_c(option='plasma') +
scale_x_continuous(breaks=dir.breaks, labels=dir.labels, limits=c(0,360)) +
theme(axis.text.y=element_blank(), axis.title=element_blank(),
axis.ticks.y=element_blank(), legend.position='none',
panel.grid.minor=element_blank()) +
ggtitle('Rottnest')
p2 <- ggplot(df, aes(CottDirection, fill=after_stat(count))) +
geom_histogram(binwidth=5) +
coord_polar() +
scale_fill_viridis_c(option='plasma') +
scale_x_continuous(breaks=dir.breaks, labels=dir.labels, limits=c(0,360)) +
theme(axis.text.y=element_blank(), axis.title=element_blank(),
axis.ticks.y=element_blank(), legend.position='none',
panel.grid.minor=element_blank()) +
ggtitle('Cottesloe')
grid.arrange(p1, p2, ncol=2)

p.rot <- ggplot(df, aes(RottDirection, y=RottPeakPeriod, colour=RottHeight)) +
geom_point(alpha=0.4) +
coord_polar() +
scale_colour_viridis_c(option='plasma') +
scale_x_continuous(breaks=dir.breaks, labels=dir.labels, limits=c(0,360)) +
scale_y_continuous(breaks=seq(0, 30, 5), limits=c(0,30)) +
ylab('Peak period (s)') +
theme(legend.position='none',
axis.title.x=element_blank(),
axis.title.y=element_text(colour='#9f9f9f'),
axis.text.y=element_text(colour='#9f9f9f'),
axis.ticks=element_line(colour='#9f9f9f'),
panel.grid.minor=element_blank()) +
ggtitle('Rottnest')
p.cot <- ggplot(df, aes(CottDirection, y=CottPeakPeriod, colour=CottHeight)) +
geom_point(alpha=0.4) +
coord_polar() +
scale_colour_viridis_c(option='plasma') +
scale_x_continuous(breaks=dir.breaks, labels=dir.labels, limits=c(0,360)) +
scale_y_continuous(breaks=seq(0, 30, 5), limits=c(0,30)) +
ylab('Peak period (s)') +
theme(legend.position='none',
axis.title.x=element_blank(),
axis.title.y=element_text(colour='#9f9f9f'),
axis.text.y=element_text(colour='#9f9f9f'),
axis.ticks=element_line(colour='#9f9f9f'),
panel.grid.minor=element_blank()) +
ggtitle('Cottesloe')
grid.arrange(p.rot, p.cot, ncol=2)

We note some perculiar outliers in Cottesloe, with large swells supposedly coming from the NE (highly unlikely).
Relationship between Rottnest and Cottesloe direction
p.xy.dir <- ggplot(df, aes(RottDirection, CottDirection, colour=abs(RottDirection-CottDirection))) +
geom_point(alpha=0.5) +
scale_x_continuous(breaks=seq(0, 360, 90), limits=c(0,360)) +
scale_y_continuous(breaks=seq(0, 360, 90), limits=c(0,360)) +
scale_colour_viridis_c(option='plasma') +
theme(legend.position='none')
p.xy.dir

Total distribution of Direction
all.dir <- df[c('RottDirection','CottDirection')] %>% reshape2::melt()
No id variables; using all as measure variables
all.dir <- all.dir %>% rename(degrees=value)
p.all.dir <- ggplot(all.dir, aes(degrees, fill=after_stat(count))) +
geom_histogram(binwidth=5) +
scale_x_continuous(breaks=dir.breaks, labels=dir.labels, limits=c(0,360)) +
coord_polar() +
scale_fill_viridis_c(option='plasma') +
theme(axis.text.y=element_blank(), axis.title=element_blank(),
axis.ticks.y=element_blank(), legend.position='none') +
ggtitle('Rottnest & Cottesloe')
p.all.dir

Searching for suitable angle to rotate axis
(Where there is a lack of data)
dir.bins <- all.dir %>%
mutate(bin=cut(degrees, seq(0,360,20), labels=seq(1,360,20)),
bin=as.numeric(as.character(bin))-1) %>%
group_by(bin) %>%
summarise(freq=n())
dir.p1 <- ggplot(all.dir, aes(degrees, fill=after_stat(count))) +
geom_histogram(binwidth=10) +
geom_vline(aes(xintercept=40), colour='tomato', lwd=1) +
scale_x_continuous(breaks=dir.breaks, limits=c(0,360)) +
ylim(c(0,100)) +
coord_polar() +
scale_fill_viridis_c(option='plasma') +
theme(axis.text.y=element_blank(), axis.title=element_blank(),
axis.ticks.y=element_blank(), legend.position='none')
dir.p2 <- ggplot(all.dir, aes(degrees, fill=after_stat(count))) +
geom_histogram(binwidth=10) +
geom_vline(aes(xintercept=40), colour='tomato', lwd=1) +
coord_cartesian(ylim=c(0,100)) +
scale_fill_viridis_c(option='plasma') +
theme(axis.text.y=element_blank(), axis.title=element_blank(),
axis.ticks.y=element_blank(), legend.position='none') +
ggtitle('Least common swell directions')
grid.arrange(dir.p2, dir.p1, ncol=2)

40 degrees is found to be a suitable candidate for axis rotation.
rotate.degrees <- function(deg, rotate) {
deg <- deg + rotate
if (deg >= 360) {
deg <- deg - 360
} else if (deg < 0) {
deg <- deg + 360
}
return (deg)
}
all.dir$rotated <- all.dir$degrees %>% sapply(rotate.degrees, rotate=-40)
p.all.dir.rotated <- ggplot(all.dir, aes(rotated, fill=after_stat(count))) +
geom_histogram(binwidth=5) +
scale_x_continuous(breaks=dir.breaks, limits=c(0,360)) +
geom_vline(aes(xintercept=0), colour='tomato', lwd=1) +
coord_polar() +
coord_polar(start=40*pi/180) +
scale_fill_viridis_c(option='plasma') +
theme(axis.text.y=element_blank(), axis.title=element_blank(),
axis.ticks.y=element_blank(), legend.position='none') +
ggtitle('Rottnest & Cottesloe, rotated -40°')
Coordinate system already present. Adding new coordinate system, which will replace the existing one.
grid.arrange(
p.all.dir +
scale_x_continuous(breaks=dir.breaks, limits=c(0,360)) +
geom_vline(aes(xintercept=0), colour='tomato', lwd=1),
p.all.dir.rotated,
ncol=2
)

p.xy.dir.rotated <- ggplot(df, aes(
x=RottDirection %>% sapply(rotate.degrees, rotate=-40),
y=CottDirection %>% sapply(rotate.degrees, rotate=-40),
colour=abs(RottDirection-CottDirection))) +
geom_point(alpha=0.5) +
scale_colour_viridis_c(option='plasma') +
theme(legend.position='none') +
labs(x='Rottnest Direction rotated -40°',
y='Cottesloe Direction rotated -40°',
title='After -40° rotation')
grid.arrange(p.xy.dir + ggtitle('Before rotation'), p.xy.dir.rotated, ncol=2)

with(df, abs(RottDirection - CottDirection) %>% mean())
[1] 18.90977
with(df, abs(
sapply(RottDirection, rotate.degrees, rotate=-40) -
sapply(CottDirection, rotate.degrees, rotate=-40)) %>% mean())
[1] 18.84041
Convert to radians
[-pi, pi)
all.dir$radians <- (all.dir$degrees * pi / 180) - pi
all.dir$rotated.radians <- (all.dir$rotated * pi / 180) - pi
radian.grid <- seq(-pi, pi, length.out=5) %>% round(2)
radian.labels <- c('-Ï€', '-Ï€/2', '0', 'Ï€/2', 'Ï€')
radian.labels.polar <- c('', '-Ï€/2', '0', 'Ï€/2', 'Ï€, -Ï€')
p.all.dir.radians <- ggplot(all.dir, aes(radians, fill=after_stat(count))) +
geom_histogram(binwidth=2*pi/(360/5)) +
scale_x_continuous(breaks=radian.grid, labels=radian.labels.polar, limits=c(-pi, pi)) +
geom_vline(aes(xintercept=pi), colour='darkgrey', lwd=1) +
coord_polar() + scale_fill_viridis_c(option='plasma') +
theme(axis.text.y=element_blank(), axis.title=element_blank(),
axis.ticks.y=element_blank(), legend.position='none') +
ggtitle('Radians, no rotation')
p.all.dir.rotated.radians <- ggplot(all.dir, aes(rotated.radians, fill=after_stat(count))) +
geom_histogram(binwidth=2*pi/(360/5)) +
scale_x_continuous(breaks=radian.grid, labels=radian.labels.polar, limits=c(-pi, pi)) +
geom_vline(aes(xintercept=pi), colour='darkgrey', lwd=1) +
coord_polar(start=40*pi/180) + scale_fill_viridis_c(option='plasma') +
theme(axis.text.y=element_blank(), axis.title=element_blank(),
axis.ticks.y=element_blank(), legend.position='none') +
ggtitle('Radians, after -40° rotation')
grid.arrange(p.all.dir.radians, p.all.dir.rotated.radians, ncol=2)

df.dir.processed <- df %>% mutate(
CottRadians=(CottDirection * pi / 180) - pi,
RottRadians=(RottDirection * pi / 180) - pi,
CottRadiansRotated=(sapply(CottDirection, rotate.degrees, rotate=-40) * pi / 180) - pi,
RottRadiansRotated=(sapply(RottDirection, rotate.degrees, rotate=-40) * pi / 180) - pi,
)
Projecting Direction onto the unit circle
p.cott.circ3 <- ggplot(df.dir.processed, aes(sin(pi*CottDirection/180), cos(pi*CottDirection/180))) +
geom_point(colour='#d34f72', alpha=0.3, size=2.5) +
ggtitle('Cottesloe') + labs(x='sin(Cottesloe Radians)', y='cos(Cottesloe Radians)')
p.rott.circ3 <- ggplot(df.dir.processed, aes(sin(pi*RottDirection / 180), cos(pi*RottDirection/180))) +
geom_point(colour='#5012a0', alpha=0.3, size=2.5) +
ggtitle('Rottnest') + labs(x='sin(Rottnest Radians)', y='cos(Rottnest Radians)')
grid.arrange(p.cott.circ3, p.rott.circ3, ncol=2)

df.dir.processed <- df.dir.processed %>%
mutate(
sinCottRad=sin(CottRadians),
cosCottRad=cos(CottRadians),
sinRottRad=sin(RottRadians),
cosRottRad=cos(RottRadians)
)
write_csv(df.dir.processed, '../ocean-waves-dir-processed.csv')
LS0tCnRpdGxlOiAiRGlyZWN0aW9uYWwgRURBIgpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sKLS0tCgpgYGB7ciBpbmNsdWRlPUZBTFNFfQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShsdWJyaWRhdGUpCmxpYnJhcnkocmV0aWN1bGF0ZSkKbGlicmFyeShncmlkRXh0cmEpCmBgYAoKYGBge3J9CmRmIDwtIHJlYWRfY3N2KCcuLi9vY2Vhbi13YXZlcy5jc3YnKQpgYGAKCmBgYHtyfQpkaXIuYnJlYWtzIDwtIHNlcSgwLCAzNjAsIGxlbmd0aC5vdXQ9OSkKZGlyLmxhYmVscyA8LSBjKCdOJywnTkUnLCdFJywnU0UnLCdTJywnU1cnLCdXJywnTlcnLCcnKQpgYGAKCiMgRGlzdHJpYnV0aW9uIG9mIGRpcmVjdGlvbiBwZXIgbG9jYXRpb24KCmBgYHtyIGZpZy53aWR0aD01fQpwMSA8LSBnZ3Bsb3QoZGYsIGFlcyhSb3R0RGlyZWN0aW9uLCBmaWxsPWFmdGVyX3N0YXQoY291bnQpKSkgKwogICAgZ2VvbV9oaXN0b2dyYW0oYmlud2lkdGg9NSkgKyAKICAgIGNvb3JkX3BvbGFyKCkgKwogICAgc2NhbGVfZmlsbF92aXJpZGlzX2Mob3B0aW9uPSdwbGFzbWEnKSArCiAgICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzPWRpci5icmVha3MsIGxhYmVscz1kaXIubGFiZWxzLCBsaW1pdHM9YygwLDM2MCkpICsKICAgIHRoZW1lKGF4aXMudGV4dC55PWVsZW1lbnRfYmxhbmsoKSwgYXhpcy50aXRsZT1lbGVtZW50X2JsYW5rKCksCiAgICAgICAgICBheGlzLnRpY2tzLnk9ZWxlbWVudF9ibGFuaygpLCBsZWdlbmQucG9zaXRpb249J25vbmUnLAogICAgICAgICAgcGFuZWwuZ3JpZC5taW5vcj1lbGVtZW50X2JsYW5rKCkpICsKICAgIGdndGl0bGUoJ1JvdHRuZXN0JykKCnAyIDwtIGdncGxvdChkZiwgYWVzKENvdHREaXJlY3Rpb24sIGZpbGw9YWZ0ZXJfc3RhdChjb3VudCkpKSArCiAgICBnZW9tX2hpc3RvZ3JhbShiaW53aWR0aD01KSArIAogICAgY29vcmRfcG9sYXIoKSArCiAgICBzY2FsZV9maWxsX3ZpcmlkaXNfYyhvcHRpb249J3BsYXNtYScpICsKICAgIHNjYWxlX3hfY29udGludW91cyhicmVha3M9ZGlyLmJyZWFrcywgbGFiZWxzPWRpci5sYWJlbHMsIGxpbWl0cz1jKDAsMzYwKSkgKwogICAgdGhlbWUoYXhpcy50ZXh0Lnk9ZWxlbWVudF9ibGFuaygpLCBheGlzLnRpdGxlPWVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgIGF4aXMudGlja3MueT1lbGVtZW50X2JsYW5rKCksIGxlZ2VuZC5wb3NpdGlvbj0nbm9uZScsCiAgICAgICAgICBwYW5lbC5ncmlkLm1pbm9yPWVsZW1lbnRfYmxhbmsoKSkgKwogICAgZ2d0aXRsZSgnQ290dGVzbG9lJykKCmdyaWQuYXJyYW5nZShwMSwgcDIsIG5jb2w9MikKYGBgCgpgYGB7ciBmaWcud2lkdGg9NX0KcC5yb3QgPC0gZ2dwbG90KGRmLCBhZXMoUm90dERpcmVjdGlvbiwgeT1Sb3R0UGVha1BlcmlvZCwgY29sb3VyPVJvdHRIZWlnaHQpKSArCiAgICBnZW9tX3BvaW50KGFscGhhPTAuNCkgKyAKICAgIGNvb3JkX3BvbGFyKCkgKwogICAgc2NhbGVfY29sb3VyX3ZpcmlkaXNfYyhvcHRpb249J3BsYXNtYScpICsKICAgIHNjYWxlX3hfY29udGludW91cyhicmVha3M9ZGlyLmJyZWFrcywgbGFiZWxzPWRpci5sYWJlbHMsIGxpbWl0cz1jKDAsMzYwKSkgKwogICAgc2NhbGVfeV9jb250aW51b3VzKGJyZWFrcz1zZXEoMCwgMzAsIDUpLCBsaW1pdHM9YygwLDMwKSkgKwogICAgeWxhYignUGVhayBwZXJpb2QgKHMpJykgKwogICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSdub25lJywKICAgICAgICBheGlzLnRpdGxlLng9ZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGl0bGUueT1lbGVtZW50X3RleHQoY29sb3VyPScjOWY5ZjlmJyksCiAgICAgICAgYXhpcy50ZXh0Lnk9ZWxlbWVudF90ZXh0KGNvbG91cj0nIzlmOWY5ZicpLAogICAgICAgIGF4aXMudGlja3M9ZWxlbWVudF9saW5lKGNvbG91cj0nIzlmOWY5ZicpLAogICAgICAgIHBhbmVsLmdyaWQubWlub3I9ZWxlbWVudF9ibGFuaygpKSArCiAgICBnZ3RpdGxlKCdSb3R0bmVzdCcpCgpwLmNvdCA8LSBnZ3Bsb3QoZGYsIGFlcyhDb3R0RGlyZWN0aW9uLCB5PUNvdHRQZWFrUGVyaW9kLCBjb2xvdXI9Q290dEhlaWdodCkpICsKICAgIGdlb21fcG9pbnQoYWxwaGE9MC40KSArIAogICAgY29vcmRfcG9sYXIoKSArCiAgICBzY2FsZV9jb2xvdXJfdmlyaWRpc19jKG9wdGlvbj0ncGxhc21hJykgKwogICAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcz1kaXIuYnJlYWtzLCBsYWJlbHM9ZGlyLmxhYmVscywgbGltaXRzPWMoMCwzNjApKSArCiAgICBzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzPXNlcSgwLCAzMCwgNSksIGxpbWl0cz1jKDAsMzApKSArCiAgICB5bGFiKCdQZWFrIHBlcmlvZCAocyknKSArCiAgICB0aGVtZShsZWdlbmQucG9zaXRpb249J25vbmUnLAogICAgICAgIGF4aXMudGl0bGUueD1lbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50aXRsZS55PWVsZW1lbnRfdGV4dChjb2xvdXI9JyM5ZjlmOWYnKSwKICAgICAgICBheGlzLnRleHQueT1lbGVtZW50X3RleHQoY29sb3VyPScjOWY5ZjlmJyksCiAgICAgICAgYXhpcy50aWNrcz1lbGVtZW50X2xpbmUoY29sb3VyPScjOWY5ZjlmJyksCiAgICAgICAgcGFuZWwuZ3JpZC5taW5vcj1lbGVtZW50X2JsYW5rKCkpICsKICAgIGdndGl0bGUoJ0NvdHRlc2xvZScpCgpncmlkLmFycmFuZ2UocC5yb3QsIHAuY290LCBuY29sPTIpCmBgYAoKV2Ugbm90ZSBzb21lIHBlcmN1bGlhciBvdXRsaWVycyBpbiBDb3R0ZXNsb2UsIHdpdGggbGFyZ2Ugc3dlbGxzIHN1cHBvc2VkbHkgY29taW5nIGZyb20gdGhlIE5FIChoaWdobHkgdW5saWtlbHkpLgoKCiMjIFJlbGF0aW9uc2hpcCBiZXR3ZWVuIFJvdHRuZXN0IGFuZCBDb3R0ZXNsb2UgZGlyZWN0aW9uCmBgYHtyIGZpZy53aWR0aD01fQpwLnh5LmRpciA8LSBnZ3Bsb3QoZGYsIGFlcyhSb3R0RGlyZWN0aW9uLCBDb3R0RGlyZWN0aW9uLCBjb2xvdXI9YWJzKFJvdHREaXJlY3Rpb24tQ290dERpcmVjdGlvbikpKSArCiAgICBnZW9tX3BvaW50KGFscGhhPTAuNSkgKwogICAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcz1zZXEoMCwgMzYwLCA5MCksIGxpbWl0cz1jKDAsMzYwKSkgKwogICAgc2NhbGVfeV9jb250aW51b3VzKGJyZWFrcz1zZXEoMCwgMzYwLCA5MCksIGxpbWl0cz1jKDAsMzYwKSkgKwogICAgc2NhbGVfY29sb3VyX3ZpcmlkaXNfYyhvcHRpb249J3BsYXNtYScpICsKICAgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0nbm9uZScpCgpwLnh5LmRpcgpgYGAKCiMgVG90YWwgZGlzdHJpYnV0aW9uIG9mIERpcmVjdGlvbgoKYGBge3J9CmFsbC5kaXIgPC0gZGZbYygnUm90dERpcmVjdGlvbicsJ0NvdHREaXJlY3Rpb24nKV0gJT4lIHJlc2hhcGUyOjptZWx0KCkKYWxsLmRpciA8LSBhbGwuZGlyICU+JSByZW5hbWUoZGVncmVlcz12YWx1ZSkKYGBgCgpgYGB7ciBmaWcud2lkdGg9NX0KcC5hbGwuZGlyIDwtIGdncGxvdChhbGwuZGlyLCBhZXMoZGVncmVlcywgZmlsbD1hZnRlcl9zdGF0KGNvdW50KSkpICsKICAgIGdlb21faGlzdG9ncmFtKGJpbndpZHRoPTUpICsgCiAgICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzPWRpci5icmVha3MsIGxhYmVscz1kaXIubGFiZWxzLCBsaW1pdHM9YygwLDM2MCkpICsKICAgIGNvb3JkX3BvbGFyKCkgKwogICAgc2NhbGVfZmlsbF92aXJpZGlzX2Mob3B0aW9uPSdwbGFzbWEnKSArCiAgICB0aGVtZShheGlzLnRleHQueT1lbGVtZW50X2JsYW5rKCksIGF4aXMudGl0bGU9ZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgYXhpcy50aWNrcy55PWVsZW1lbnRfYmxhbmsoKSwgbGVnZW5kLnBvc2l0aW9uPSdub25lJykgKwogICAgZ2d0aXRsZSgnUm90dG5lc3QgJiBDb3R0ZXNsb2UnKQoKcC5hbGwuZGlyCmBgYAoKIyBTZWFyY2hpbmcgZm9yIHN1aXRhYmxlIGFuZ2xlIHRvIHJvdGF0ZSBheGlzCihXaGVyZSB0aGVyZSBpcyBhIGxhY2sgb2YgZGF0YSkKCmBgYHtyfQpkaXIuYmlucyA8LSBhbGwuZGlyICU+JSAKICAgIG11dGF0ZShiaW49Y3V0KGRlZ3JlZXMsIHNlcSgwLDM2MCwyMCksIGxhYmVscz1zZXEoMSwzNjAsMjApKSwKICAgICAgICAgICBiaW49YXMubnVtZXJpYyhhcy5jaGFyYWN0ZXIoYmluKSktMSkgJT4lCiAgICBncm91cF9ieShiaW4pICU+JQogICAgc3VtbWFyaXNlKGZyZXE9bigpKQpgYGAKCmBgYHtyIGZpZy53aWR0aD01fQpkaXIucDEgPC0gZ2dwbG90KGFsbC5kaXIsIGFlcyhkZWdyZWVzLCBmaWxsPWFmdGVyX3N0YXQoY291bnQpKSkgKwogICAgZ2VvbV9oaXN0b2dyYW0oYmlud2lkdGg9MTApICsKICAgIGdlb21fdmxpbmUoYWVzKHhpbnRlcmNlcHQ9NDApLCBjb2xvdXI9J3RvbWF0bycsIGx3ZD0xKSArCiAgICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzPWRpci5icmVha3MsIGxpbWl0cz1jKDAsMzYwKSkgKwogICAgeWxpbShjKDAsMTAwKSkgKwogICAgY29vcmRfcG9sYXIoKSArCiAgICBzY2FsZV9maWxsX3ZpcmlkaXNfYyhvcHRpb249J3BsYXNtYScpICsKICAgIHRoZW1lKGF4aXMudGV4dC55PWVsZW1lbnRfYmxhbmsoKSwgYXhpcy50aXRsZT1lbGVtZW50X2JsYW5rKCksCiAgICAgICAgICBheGlzLnRpY2tzLnk9ZWxlbWVudF9ibGFuaygpLCBsZWdlbmQucG9zaXRpb249J25vbmUnKQoKZGlyLnAyIDwtIGdncGxvdChhbGwuZGlyLCBhZXMoZGVncmVlcywgZmlsbD1hZnRlcl9zdGF0KGNvdW50KSkpICsKICAgIGdlb21faGlzdG9ncmFtKGJpbndpZHRoPTEwKSArCiAgICBnZW9tX3ZsaW5lKGFlcyh4aW50ZXJjZXB0PTQwKSwgY29sb3VyPSd0b21hdG8nLCBsd2Q9MSkgKwogICAgY29vcmRfY2FydGVzaWFuKHlsaW09YygwLDEwMCkpICsKICAgIHNjYWxlX2ZpbGxfdmlyaWRpc19jKG9wdGlvbj0ncGxhc21hJykgKwogICAgdGhlbWUoYXhpcy50ZXh0Lnk9ZWxlbWVudF9ibGFuaygpLCBheGlzLnRpdGxlPWVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgIGF4aXMudGlja3MueT1lbGVtZW50X2JsYW5rKCksIGxlZ2VuZC5wb3NpdGlvbj0nbm9uZScpICsKICAgIGdndGl0bGUoJ0xlYXN0IGNvbW1vbiBzd2VsbCBkaXJlY3Rpb25zJykKCmdyaWQuYXJyYW5nZShkaXIucDIsIGRpci5wMSwgbmNvbD0yKQpgYGAKNDAgZGVncmVlcyBpcyBmb3VuZCB0byBiZSBhIHN1aXRhYmxlIGNhbmRpZGF0ZSBmb3IgYXhpcyByb3RhdGlvbi4gCgpgYGB7cn0Kcm90YXRlLmRlZ3JlZXMgPC0gZnVuY3Rpb24oZGVnLCByb3RhdGUpIHsKICAgIGRlZyA8LSBkZWcgKyByb3RhdGUKICAgIGlmIChkZWcgPj0gMzYwKSB7CiAgICAgICAgZGVnIDwtIGRlZyAtIDM2MAogICAgfSBlbHNlIGlmIChkZWcgPCAwKSB7CiAgICAgICAgZGVnIDwtIGRlZyArIDM2MAogICAgfQogICAgcmV0dXJuIChkZWcpCn0KYGBgCgpgYGB7cn0KYWxsLmRpciRyb3RhdGVkIDwtIGFsbC5kaXIkZGVncmVlcyAlPiUgc2FwcGx5KHJvdGF0ZS5kZWdyZWVzLCByb3RhdGU9LTQwKQpgYGAKCmBgYHtyIGZpZy53aWR0aD01fQpwLmFsbC5kaXIucm90YXRlZCA8LSBnZ3Bsb3QoYWxsLmRpciwgYWVzKHJvdGF0ZWQsIGZpbGw9YWZ0ZXJfc3RhdChjb3VudCkpKSArCiAgICBnZW9tX2hpc3RvZ3JhbShiaW53aWR0aD01KSArIAogICAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcz1kaXIuYnJlYWtzLCBsaW1pdHM9YygwLDM2MCkpICsKICAgIGdlb21fdmxpbmUoYWVzKHhpbnRlcmNlcHQ9MCksIGNvbG91cj0ndG9tYXRvJywgbHdkPTEpICsKICAgIGNvb3JkX3BvbGFyKCkgKwogICAgY29vcmRfcG9sYXIoc3RhcnQ9NDAqcGkvMTgwKSArCiAgICBzY2FsZV9maWxsX3ZpcmlkaXNfYyhvcHRpb249J3BsYXNtYScpICsKICAgIHRoZW1lKGF4aXMudGV4dC55PWVsZW1lbnRfYmxhbmsoKSwgYXhpcy50aXRsZT1lbGVtZW50X2JsYW5rKCksCiAgICAgICAgICBheGlzLnRpY2tzLnk9ZWxlbWVudF9ibGFuaygpLCBsZWdlbmQucG9zaXRpb249J25vbmUnKSArCiAgICBnZ3RpdGxlKCdSb3R0bmVzdCAmIENvdHRlc2xvZSwgcm90YXRlZCAtNDDCsCcpCgpncmlkLmFycmFuZ2UoCiAgICBwLmFsbC5kaXIgKwogICAgICAgIHNjYWxlX3hfY29udGludW91cyhicmVha3M9ZGlyLmJyZWFrcywgbGltaXRzPWMoMCwzNjApKSArCiAgICAgICAgZ2VvbV92bGluZShhZXMoeGludGVyY2VwdD0wKSwgY29sb3VyPSd0b21hdG8nLCBsd2Q9MSksCiAgICBwLmFsbC5kaXIucm90YXRlZCwKICAgIG5jb2w9MgopCmBgYAoKYGBge3IgZmlnLndpZHRoPTUsIGZpZy5oZWlnaHQ9Mi41fQpwLnh5LmRpci5yb3RhdGVkIDwtIGdncGxvdChkZiwgYWVzKAogICAgICAgIHg9Um90dERpcmVjdGlvbiAlPiUgc2FwcGx5KHJvdGF0ZS5kZWdyZWVzLCByb3RhdGU9LTQwKSwKICAgICAgICB5PUNvdHREaXJlY3Rpb24gJT4lIHNhcHBseShyb3RhdGUuZGVncmVlcywgcm90YXRlPS00MCksCiAgICAgICAgY29sb3VyPWFicyhSb3R0RGlyZWN0aW9uLUNvdHREaXJlY3Rpb24pKSkgKwogICAgZ2VvbV9wb2ludChhbHBoYT0wLjUpICsKICAgIHNjYWxlX2NvbG91cl92aXJpZGlzX2Mob3B0aW9uPSdwbGFzbWEnKSArCiAgICB0aGVtZShsZWdlbmQucG9zaXRpb249J25vbmUnKSArCiAgICBsYWJzKHg9J1JvdHRuZXN0IERpcmVjdGlvbiByb3RhdGVkIC00MMKwJywKICAgICAgICAgeT0nQ290dGVzbG9lIERpcmVjdGlvbiByb3RhdGVkIC00MMKwJywKICAgICAgICAgdGl0bGU9J0FmdGVyIC00MMKwIHJvdGF0aW9uJykKCmdyaWQuYXJyYW5nZShwLnh5LmRpciArIGdndGl0bGUoJ0JlZm9yZSByb3RhdGlvbicpLCBwLnh5LmRpci5yb3RhdGVkLCBuY29sPTIpCmBgYAoKCmBgYHtyfQp3aXRoKGRmLCBhYnMoUm90dERpcmVjdGlvbiAtIENvdHREaXJlY3Rpb24pICU+JSBtZWFuKCkpCndpdGgoZGYsIGFicygKICAgIHNhcHBseShSb3R0RGlyZWN0aW9uLCByb3RhdGUuZGVncmVlcywgcm90YXRlPS00MCkgLQogICAgc2FwcGx5KENvdHREaXJlY3Rpb24sIHJvdGF0ZS5kZWdyZWVzLCByb3RhdGU9LTQwKSkgJT4lIG1lYW4oKSkKYGBgCgojIyBDb252ZXJ0IHRvIHJhZGlhbnMKIyMjIyBbLXBpLCBwaSkKYGBge3J9CmFsbC5kaXIkcmFkaWFucyA8LSAoYWxsLmRpciRkZWdyZWVzICogcGkgLyAxODApIC0gcGkKYWxsLmRpciRyb3RhdGVkLnJhZGlhbnMgPC0gKGFsbC5kaXIkcm90YXRlZCAqIHBpIC8gMTgwKSAtIHBpCmBgYAoKYGBge3J9CnJhZGlhbi5ncmlkIDwtIHNlcSgtcGksIHBpLCBsZW5ndGgub3V0PTUpICU+JSByb3VuZCgyKQpyYWRpYW4ubGFiZWxzIDwtIGMoJy3PgCcsICctz4AvMicsICcwJywgJ8+ALzInLCAnz4AnKQpyYWRpYW4ubGFiZWxzLnBvbGFyIDwtIGMoJycsICctz4AvMicsICcwJywgJ8+ALzInLCAnz4AsIC3PgCcpCmBgYAoKYGBge3IgZmlnLndpZHRoPTV9CnAuYWxsLmRpci5yYWRpYW5zIDwtIGdncGxvdChhbGwuZGlyLCBhZXMocmFkaWFucywgZmlsbD1hZnRlcl9zdGF0KGNvdW50KSkpICsKICAgIGdlb21faGlzdG9ncmFtKGJpbndpZHRoPTIqcGkvKDM2MC81KSkgKyAKICAgIHNjYWxlX3hfY29udGludW91cyhicmVha3M9cmFkaWFuLmdyaWQsIGxhYmVscz1yYWRpYW4ubGFiZWxzLnBvbGFyLCBsaW1pdHM9YygtcGksIHBpKSkgKwogICAgZ2VvbV92bGluZShhZXMoeGludGVyY2VwdD1waSksIGNvbG91cj0nZGFya2dyZXknLCBsd2Q9MSkgKwogICAgY29vcmRfcG9sYXIoKSArIHNjYWxlX2ZpbGxfdmlyaWRpc19jKG9wdGlvbj0ncGxhc21hJykgKwogICAgdGhlbWUoYXhpcy50ZXh0Lnk9ZWxlbWVudF9ibGFuaygpLCBheGlzLnRpdGxlPWVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgIGF4aXMudGlja3MueT1lbGVtZW50X2JsYW5rKCksIGxlZ2VuZC5wb3NpdGlvbj0nbm9uZScpICsKICAgIGdndGl0bGUoJ1JhZGlhbnMsIG5vIHJvdGF0aW9uJykKCnAuYWxsLmRpci5yb3RhdGVkLnJhZGlhbnMgPC0gZ2dwbG90KGFsbC5kaXIsIGFlcyhyb3RhdGVkLnJhZGlhbnMsIGZpbGw9YWZ0ZXJfc3RhdChjb3VudCkpKSArCiAgICBnZW9tX2hpc3RvZ3JhbShiaW53aWR0aD0yKnBpLygzNjAvNSkpICsgCiAgICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzPXJhZGlhbi5ncmlkLCBsYWJlbHM9cmFkaWFuLmxhYmVscy5wb2xhciwgbGltaXRzPWMoLXBpLCBwaSkpICsKICAgIGdlb21fdmxpbmUoYWVzKHhpbnRlcmNlcHQ9cGkpLCBjb2xvdXI9J2RhcmtncmV5JywgbHdkPTEpICsKICAgIGNvb3JkX3BvbGFyKHN0YXJ0PTQwKnBpLzE4MCkgKyBzY2FsZV9maWxsX3ZpcmlkaXNfYyhvcHRpb249J3BsYXNtYScpICsKICAgIHRoZW1lKGF4aXMudGV4dC55PWVsZW1lbnRfYmxhbmsoKSwgYXhpcy50aXRsZT1lbGVtZW50X2JsYW5rKCksCiAgICAgICAgICBheGlzLnRpY2tzLnk9ZWxlbWVudF9ibGFuaygpLCBsZWdlbmQucG9zaXRpb249J25vbmUnKSArCiAgICBnZ3RpdGxlKCdSYWRpYW5zLCBhZnRlciAtNDDCsCByb3RhdGlvbicpCgpncmlkLmFycmFuZ2UocC5hbGwuZGlyLnJhZGlhbnMsIHAuYWxsLmRpci5yb3RhdGVkLnJhZGlhbnMsIG5jb2w9MikKYGBgCgpgYGB7cn0KZGYuZGlyLnByb2Nlc3NlZCA8LSBkZiAlPiUgbXV0YXRlKAogICAgQ290dFJhZGlhbnM9KENvdHREaXJlY3Rpb24gKiBwaSAvIDE4MCkgLSBwaSwKICAgIFJvdHRSYWRpYW5zPShSb3R0RGlyZWN0aW9uICogcGkgLyAxODApIC0gcGksCiAgICBDb3R0UmFkaWFuc1JvdGF0ZWQ9KHNhcHBseShDb3R0RGlyZWN0aW9uLCByb3RhdGUuZGVncmVlcywgcm90YXRlPS00MCkgKiBwaSAvIDE4MCkgLSBwaSwKICAgIFJvdHRSYWRpYW5zUm90YXRlZD0oc2FwcGx5KFJvdHREaXJlY3Rpb24sIHJvdGF0ZS5kZWdyZWVzLCByb3RhdGU9LTQwKSAqIHBpIC8gMTgwKSAtIHBpLAopCmBgYAoKX19fCiMgUHJvamVjdGluZyBEaXJlY3Rpb24gb250byB0aGUgdW5pdCBjaXJjbGUKCmBgYHtyIGZpZy5oZWlnaHQ9MywgZmlnLndpZHRoPTZ9CnAuY290dC5jaXJjMyA8LSBnZ3Bsb3QoZGYuZGlyLnByb2Nlc3NlZCwgYWVzKHNpbihwaSpDb3R0RGlyZWN0aW9uLzE4MCksIGNvcyhwaSpDb3R0RGlyZWN0aW9uLzE4MCkpKSArCiAgICBnZW9tX3BvaW50KGNvbG91cj0nI2QzNGY3MicsIGFscGhhPTAuMywgc2l6ZT0yLjUpICsKICAgIGdndGl0bGUoJ0NvdHRlc2xvZScpICsgbGFicyh4PSdzaW4oQ290dGVzbG9lIFJhZGlhbnMpJywgeT0nY29zKENvdHRlc2xvZSBSYWRpYW5zKScpCnAucm90dC5jaXJjMyA8LSBnZ3Bsb3QoZGYuZGlyLnByb2Nlc3NlZCwgYWVzKHNpbihwaSpSb3R0RGlyZWN0aW9uLzE4MCksIGNvcyhwaSpSb3R0RGlyZWN0aW9uLzE4MCkpKSArCiAgICBnZW9tX3BvaW50KGNvbG91cj0nIzUwMTJhMCcsIGFscGhhPTAuMywgc2l6ZT0yLjUpICsKICAgIGdndGl0bGUoJ1JvdHRuZXN0JykgKyBsYWJzKHg9J3NpbihSb3R0bmVzdCBSYWRpYW5zKScsIHk9J2NvcyhSb3R0bmVzdCBSYWRpYW5zKScpCmdyaWQuYXJyYW5nZShwLmNvdHQuY2lyYzMsIHAucm90dC5jaXJjMywgbmNvbD0yKQpgYGAKCmBgYHtyfQpkZi5kaXIucHJvY2Vzc2VkIDwtIGRmLmRpci5wcm9jZXNzZWQgJT4lIAogICAgbXV0YXRlKAogICAgICAgIHNpbkNvdHRSYWQ9c2luKENvdHRSYWRpYW5zKSwKICAgICAgICBjb3NDb3R0UmFkPWNvcyhDb3R0UmFkaWFucyksCiAgICAgICAgc2luUm90dFJhZD1zaW4oUm90dFJhZGlhbnMpLAogICAgICAgIGNvc1JvdHRSYWQ9Y29zKFJvdHRSYWRpYW5zKQogICAgKQpgYGAKCmBgYHtyfQp3cml0ZV9jc3YoZGYuZGlyLnByb2Nlc3NlZCwgJy4uL29jZWFuLXdhdmVzLWRpci1wcm9jZXNzZWQuY3N2JykKYGBgCgo=